#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
#include <string.h>
#include "traits.hpp"
#include "utils.hpp"

template <typename Iter>
std::string join_strings(Iter begin, Iter end, const char* const d = " ")
{
    std::ostringstream os;
    std::copy(begin, end - 1, std::ostream_iterator<std::string>(os, d));
    os << *(end - 1);
    return os.str();
}

template <typename T>
std::string join_strings(T const& cont, const char* const d = " ")
{
    static_assert(impl::is_container<T>::value, "shall be container");
    if (cont.empty())
        return {};
    return join_strings(cont.begin(), cont.end(), d);
}

using namespace std;

namespace inner
{
std::string join_str(const vector<string>& v)
{
    char buf[4096]{};
    char* p = buf;
    for (auto const& s : v)
    {
        strncat(p, s.data(), s.size());
        p += s.size();
        *p++ = ' ';
    }
    return buf;
}
}  // namespace inner

int main(int argc, char** argv)
{
    vector<string> strs{"hello", "world", "C++"};
    cout << join_strings(strs) << '\n';

    time_point start = sysclock::now();
    vector<string> strs_bench{
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++",   "hello", "world", "C++",   "hello",
        "world", "C++",   "hello", "world", "C++",   "hello", "world", "C++",
        "hello", "world", "C++",   "hello", "world", "C++",   "hello", "world",
        "C++",   "hello", "world", "C++"};
    cout << join_strings(strs_bench) << '\n';
    cout << "Benchmark\n\n";
    cout << "joining " << strs_bench.size() << " strings for 1 million times\n";
    for (int i = 0; i < 1000000; ++i)
    {
        auto ret = join_strings(strs_bench);
    }
    auto dur = sysclock::now() - start;
    cout << "time used: " << durcast(dur, 1ms).count() << "ms\n";
    // time used: 7'800 ~ 10'000ms on 4 core cpu
    // in comparison
    cout << inner::join_str(strs_bench) << '\n';
    start = sysclock::now();
    for (int i = 0; i < 1000000; ++i)
    {
        auto ret = inner::join_str(strs_bench);
    }
    dur = sysclock::now() - start;
    cout << "time used: " << durcast(dur, 1ms).count() << "ms\n";
    // time used: 1'900 ~ 4'500ms on 4 core cpu
    return 0;
}